﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Collections;
using Reborn_Server.App1AppHandler;
using System.Timers;

namespace App1AppHandler
{
    public class MapItem
    {
        public string TerrainType;
        public string ColorUrl;
        public string TerrainUrl;
        public string Terrain2 = "";
        public string TerrainOver = "";
        public int MapX;
        public int MapY;
        
        public volatile List<CreatureBase> CreaturesBases = new List<CreatureBase>();

        public bool Transparent;
        public int Motion;
        public bool HasLoot;

        public List<MapItem> mapItemsWithin4 = new List<MapItem>();
        public List<MapItem> mapItemsWithin8 = new List<MapItem>();
        public List<MapItem> mapItemsWithin12 = new List<MapItem>();

        public int PortalDistance;
        public int PortalLevelRequirement = -1;
        public string PortalSkillType = "";
        public bool allowAOE = true;

        public bool isNaturalDark = false;

        //Used by spells to effect creatures motion but not block spells like a wall would
        //Example: Ring of Fire,  reduces motion to 0 but we still want to be able to cast spells on the hex
        public int MotionCreatureOverride = -1;

        public Map parentMap;

        public Timer timerHexReset = new Timer(1000 * 60);

        //Helper to get the motion for a creatures path
        public int CreatureMotion()
        {
            if (MotionCreatureOverride != -1)
                return MotionCreatureOverride;
            else
                return Motion;
        }

        public List<Character> getCharactersWithin8()
        {
            List<Character> characters = new List<Character>();

            foreach (MapItem mapitem in mapItemsWithin8)
            {
                foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                {
                    if (creatureBase is Character)
                        characters.Add((Character)creatureBase);
                }
            }

            return characters;
        }

        public List<Character> getCharactersWithin4()
        {
            List<Character> characters = new List<Character>();

            foreach (MapItem mapitem in mapItemsWithin4)
            {
                foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                {
                    if (creatureBase is Character)
                        characters.Add((Character)creatureBase);
                }
            }

            return characters;
        }

        public string GetRootMessage()
        {
            foreach (Spell spell in SpellLayer0)
            {
                if (spell is IRootBuff)
                {
                    IRootBuff rootBuff = (IRootBuff)spell;
                    return rootBuff.RootMessage();
                }
            }
            foreach (Spell spell in SpellLayer1)
            {
                if (spell is IRootBuff)
                {
                    IRootBuff rootBuff = (IRootBuff)spell;
                    return rootBuff.RootMessage();
                }
            }

            return "";
        }

        //Under Terrain
        public volatile List<Spell> SpellLayer0 = new List<Spell>();
        //Under Characters
        public volatile List<Spell> SpellLayer1 = new List<Spell>();
        //Over Characters
        public volatile Spell SpellLayer2 = new Spell();

        public int PortalMapID;
        public int PortalX;
        public int PortalY;

        //Pass null creature base to ignore natural darkness.
        public bool isDark(CreatureBase creatureBase)
        {
            if (SpellLayer2.spellIcon != null)
            {
                if (SpellLayer2.spellIcon.Name == "Darkness")
                    return true;
            }
            if (isNaturalDark && creatureBase != null)
            {
                if (creatureBase.buffManager.HasNightVision() == true)
                    return false;

                return true;
            }

            return false;
        }

        public MapItem()
        {
            TerrainType = "";
            ColorUrl = "";
            TerrainUrl = "";
            Motion = 0;

            MapX = 0;
            MapY = 0;

            Transparent = false;

            //Creatures = new List<Creature>();
            //Characters = new List<Character>();

            PortalMapID = -1;
            PortalX = -1;
            PortalY = -1;
            PortalDistance = -1;
            HasLoot = false;

            timerHexReset.AutoReset = false;
            timerHexReset.Elapsed += new ElapsedEventHandler(timerHexReset_Elapsed);
        }

        private void timerHexReset_Elapsed(object sender, ElapsedEventArgs e)
        {
            LockItem lockItem = parentMap.GameHandler.GetLockItem(parentMap.MapID, parentMap.MapInstance);
            lock (lockItem.LockObj)
            {
                if (this.TerrainType == "SDoor")
                {
                    //Cannot close the secret door, people are standing in the doorway
                    if (this.CreaturesBases.Count > 0)
                    {
                        timerHexReset.Start();
                        return;
                    }
                    //Door is already closed dont resart the timer
                    if (TerrainUrl.IndexOf("Open") == -1)
                        return;

                    Transparent = false;
                    Motion = 0;
                    TerrainUrl = TerrainUrl.Replace("_Open", "");

                    foreach (MapItem mapitem in parentMap.MapItems)
                    {
                        if (Math.Abs(mapitem.MapX - MapX) <= 8 && Math.Abs(mapitem.MapY - MapY) <= 8)
                        {
                            foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                            {
                                if (creatureBase is Character)
                                {
                                    Character character = (Character)creatureBase;
                                    character.PlaySound("DoorClose", MapX, MapY);
                                }
                            }
                        }
                        if (Math.Abs(mapitem.MapX - MapX) <= 4 && Math.Abs(mapitem.MapY - MapY) <= 4)
                        {
                            foreach (CreatureBase creatureBase in mapitem.CreaturesBases)
                            {
                                if (creatureBase is Character)
                                {
                                    Character character = (Character)creatureBase;
                                    character.AddMapItem(this);
                                }
                            }
                        }
                    }
                }
            }//End Lock
        }

        public bool RemoveSpellByID(long spellGUID)
        {
            for (int x = 0; x < SpellLayer0.Count; x++)
            {
                if (SpellLayer0[x].SpellID == spellGUID)
                {
                    SpellLayer0.RemoveAt(x);
                    return true;
                }
            }
            for (int x = 0; x < SpellLayer0.Count; x++)
            {
                if (SpellLayer1[x].SpellID == spellGUID)
                {
                    SpellLayer1.RemoveAt(x);
                    return true;
                }
            }

            if (SpellLayer2 != null && SpellLayer2.spellIcon != null && SpellLayer2.SpellID == spellGUID)
            {
                SpellLayer2 = new Spell();
                return true;
            }

            return false;
        }

        public bool ContainsSpellByID(long spellGUID)
        {
            foreach (Spell spell in SpellLayer0)
            {
                if (spell.SpellID == spellGUID)
                    return true;
            }

            foreach (Spell spell in SpellLayer1)
            {
                if (spell.SpellID == spellGUID)
                    return true;
            }

            if (SpellLayer2 != null && SpellLayer2.spellIcon != null && SpellLayer2.SpellID == spellGUID)
                return true;


            return false;
        }
        public bool ContainsSpellByStackType(string stackType)
        {
            foreach (Spell spell in SpellLayer0)
            {
                if (spell.spellIcon.StackType == stackType)
                    return true;
            }

            foreach (Spell spell in SpellLayer1)
            {
                if (spell.spellIcon.StackType == stackType)
                    return true;
            }

            if (SpellLayer2 != null && SpellLayer2.spellIcon != null && SpellLayer2.spellIcon.StackType == stackType)
                return true;


            return false;
        }

        public bool MeetsPortalRequirements(Character character)
        {
            if (this.PortalLevelRequirement == -1)
                return true;

            if (this.PortalSkillType == "Any")
            {
                if (PortalLevelRequirement > character.skillManager.getMaxSkill())
                    return false;
            }
            else
            {
                int currentSkillLevel = System.Convert.ToInt32(Math.Floor(character.skillManager.GetCurrentLevel(this.PortalSkillType)));
                if (currentSkillLevel < PortalLevelRequirement)
                    return false;
            }

            return true;
        }

        public string toXML(Character sendingToCharacter)
        {
            string result = "";

            StringWriter stringWriter = new StringWriter();
            XmlTextWriter xmldoc = new XmlTextWriter(stringWriter);

            xmldoc.WriteStartElement("m");
            xmldoc.WriteAttributeString("t", TerrainType.ToString());
            xmldoc.WriteAttributeString("g", ColorUrl.ToString());
            xmldoc.WriteAttributeString("o", TerrainUrl.ToString());
            xmldoc.WriteAttributeString("k", Terrain2.ToString());
            xmldoc.WriteAttributeString("i", TerrainOver.ToString());
            xmldoc.WriteAttributeString("x", MapX.ToString());
            xmldoc.WriteAttributeString("y", MapY.ToString());
            xmldoc.WriteAttributeString("v", Transparent.ToString());
            xmldoc.WriteAttributeString("p", PortalDistance.ToString());
            xmldoc.WriteAttributeString("m", Motion.ToString());
            xmldoc.WriteAttributeString("l", HasLoot.ToString());

            if (isDark(sendingToCharacter))
                xmldoc.WriteAttributeString("s2", "Darkness");
            else
                xmldoc.WriteAttributeString("s2", "");

            xmldoc.WriteStartElement("s0");
            lock(SpellLayer0)
            {
                foreach (Spell spell in SpellLayer0)
                {
                    xmldoc.WriteStartElement("s");
                    xmldoc.WriteString(spell.spellIcon.FieldImageURL);
                    xmldoc.WriteEndElement();
                }
            }
            xmldoc.WriteEndElement();

            xmldoc.WriteStartElement("s1");
            lock (SpellLayer1)
            {
                foreach (Spell spell in SpellLayer1)
                {
                    xmldoc.WriteStartElement("s");
                    xmldoc.WriteString(spell.spellIcon.FieldImageURL);
                    xmldoc.WriteEndElement();
                }
            }
            xmldoc.WriteEndElement();

            string innerXml = "";
            foreach (CreatureBase creaturebase in CreaturesBases)
            {
                if (creaturebase.CanSeeMe(sendingToCharacter))
                    innerXml = innerXml + creaturebase.toXML(sendingToCharacter);
            }
            xmldoc.WriteStartElement("c");
            if (innerXml != "") xmldoc.WriteRaw(innerXml);
            xmldoc.WriteEndElement();

            xmldoc.WriteEndElement();
            xmldoc.Flush();

            xmldoc.Close();

            stringWriter.Flush();

            result = stringWriter.ToString();

            return result;
        }

        public static string getDirection(MapItem start, MapItem end)
        {
            string result = "";

            float xPos = end.MapX - start.MapX;
            float yPos = end.MapY - start.MapY;
            float MaxDistance = Math.Max(Math.Abs(xPos), Math.Abs(yPos));

            if (xPos == 0 && yPos == 0)
                return result;

            if ((yPos / MaxDistance) < -.51)
                result = result + "N";
            if ((yPos / MaxDistance) > +.51)
                result = result + "S";
            if ((xPos / MaxDistance) < -.51)
                result = result + "W";
            if ((xPos / MaxDistance) > +.51)
                result = result + "E";
            
            return result;
        }
    }

}
